<script setup lang="ts" name="ImgEdit">
import MenuBar from '@/views/components/menuBar/index.vue'
import Resolution from './components/resolution/index.vue'
import { onTabMessage, openChildWindow } from '@/utils/windowTool'
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { createPassportPageBase64 } from './frame/passport/index'

/*========================================>( 模板属性 )<========================================*/
//标题栏配置
const menuBarMenus = ref<Array<any>>([
	{
		name: '文件',
		icon: 'fold',
		childrens: [
			{ name: '打开图像', mark: 'open', icon: 'fold-open' },
			{ name: '保存', mark: 'save', icon: 'save' },
			{ name: '另存为..', mark: 'save-as', icon: 'save-to' },
			{ name: '打印', mark: 'print', icon: 'print' },
			{ name: '图像信息', mark: 'info', icon: 'info' },
		]
	},
	{
		name: '框选',
		icon: 'select',
		childrens: [
			{ name: '取消框选', mark: 'cancel-select', icon: 'cancel-square' },
			{ name: '自由比例', mark: 'select-type-freedom', type: 'checkbox', value: true },
			{ name: '正方比例', mark: 'select-type-square', type: 'checkbox', value: false },
			{ name: '两寸照', mark: 'select-type-2inch', type: 'checkbox', value: false },
			{ name: '一寸照', mark: 'select-type-1inch', type: 'checkbox', value: false },
			{ name: '自定义', mark: 'select-type-yourself', type: 'checkbox', value: false },
		]
	},
	{
		name: '操作',
		icon: 'hand',
		childrens: [
			{ name: '显示工具箱', mark: 'show-toolpad', type: 'checkbox', value: false },
			{ name: '撤销操作', mark: 'cancel', icon: 'cancel-record' },
			{ name: '撤销所有操作', mark: 'cancel-all', icon: 'cancel-record-all' },
			{ name: '还原操作', mark: 'revert', icon: 'revert-record' }
		]
	},
	{
		name: '其他',
		icon: 'help',
		childrens: [
			{ name: '识别文字', mark: 'to-text', icon: 'ocr' },
			{ name: '识别二维码', mark: 'to-erm', icon: 'qrcode' },
			{ name: '设置为桌面背景', mark: 'set-system', icon: 'computer' },
			{ name: '快捷键设置', mark: 'hotkey', icon: 'hotkey' }
		]
	}
])

//图像数据
const imageData = ref<any>()

//原文件路径
const fileName = ref<string>()

//绘制内容
const canvasBlock = ref<{ [key: string]: any }>({
	w: 0,//canvas宽
	h: 0,//canvas高
	rw: 0,//图片宽
	rh: 0,//图片高
	scale: 1,//缩放
	rotate: 0,//旋转
	image: false//是否镜像
})

//框选的类型
const selectType = ref<string>('select-type-freedom')

//框选的自定义比例
const selectRateW = ref<number>(1)
const selectRateH = ref<number>(1)

//是否显示修改像素框
const showResolution = ref<boolean>(false)

//目前图像像素
const resolution = ref<any>({ w: undefined, h: undefined })

//是否显示OCR
const showOCR = ref<boolean>(false)

//OCR内容
const ocrContent = ref<string>()

/*========================================>( 作用域属性 )<========================================*/
//文件地址
let _filePath: string | undefined = undefined
//框选是否开始
let _isSelect = false
//框选的起始坐标
let _selectStart: Array<number> | undefined = undefined
//框选的最终坐标组
let _cropLocation: Array<number> | undefined = undefined
//历史图像数据列表
let _historyList: Array<any> = []
//历史指针 _historyPointer如果跟his的最后元素指针相同为最新，undefined是未初始化
let _historyPointer = -1
//排版前提前保存证件照图像
let _passportImageCache: any = undefined


/*========================================>( dom属性 )<========================================*/
//上传组件
const domUpload = ref<HTMLElement>()
//画板
const domImageBoard = ref<HTMLCanvasElement>()
//画板幕布
const domScreen = ref<HTMLCanvasElement>()

//定义ipc
const ipcs = {
	//初始化句柄
	init: () => {
		window.ipcRenderer.send('IMGEDIT-INIT')
	},
	//关闭工具箱
	closeToolPad: () => {
		window.ipcRenderer.send('IMGEDIT-CLOSE-TOOLPAD')
	}
}

/*========================================>( 普通方法 )<========================================*/

//初始化监听
const initListener = () => {
	//监听工具箱关闭
	window.ipcRenderer.listen('TOOLPAD-CLOSE-CALL', () => {
		menuBarMenus.value[1].childrens[0].value = false
	})
	//监听工具点击
	onTabMessage('ImgEditToolClick', (mark: string) => {
		handleOperate(mark)
	})
	onTabMessage('passport', (e: any) => {
		proxy?.$modal.loading('排版中')
		setTimeout(async () => {
			makePassport(e)
		}, 100)
	})
	//监听鼠标移动
	document.addEventListener('mousedown', listenCropMouseDown)
	document.addEventListener('mousemove', listenCropMouseMove)
	document.addEventListener('mouseup', listenCropMouseUpOrLeave)
}

//工具
const handleOperate = (mark: string) => {
	switch (mark) {
		case 'open':
			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
			// @ts-ignore
			document.querySelector('.el-upload__input')?.click()
			break
		case 'show-toolpad':
			//切换工具箱开启关闭
			if (!menuBarMenus.value[1].childrens[0].value) {
				window.ipcRenderer.send('IMGEDIT-TOOL-OPEN')
				menuBarMenus.value[1].childrens[0].value = true
			} else {
				ipcs.closeToolPad()
				menuBarMenus.value[1].childrens[0].value = false
			}
			break
		case 'cancel-select':
			clearSelect()
			break;
		case 'cancel':
			backHistory()
			break
		case 'cancel-all':
			resetImage()
			break
		case 'revert':
			forwardHistory()
			break
		case 'select-type-freedom':
		case 'select-type-square':
		case 'select-type-2inch':
		case 'select-type-1inch':
		case 'select-type-yourself':
			for (const [index, { mark: m }] of menuBarMenus.value[1].childrens.entries()) {
				menuBarMenus.value[1].childrens[index].value = (mark === m)
			}
			selectType.value = mark
			break
		case 'rotate':
			dealRotate()
			break
		case 'image':
			dealImage()
			break
		case 'crop':
			dealCrop()
			break
		case 'passport':
			dealPassport()
			break
		case 'pixel':
			if (!imageData.value) return
			var { width, height } = imageData.value
			resolution.value.w = width
			resolution.value.h = height
			showResolution.value = true
			break
		case 'print':
			break
		case 'to-text':
			if (!imageData.value) return
			proxy?.$modal.loading('解析中')
			setTimeout(() => {
				ocrContent.value = window.ipcRenderer.sendSync('IMGEDIT-OCR', { path: _filePath })
				console.log('123',ocrContent.value)
				proxy?.$modal.closeLoading()
				showOCR.value = true
			}, 100)
			break
		case 'save-as':
			window.ipcRenderer.send('GENERAL-SAVE-AS', { title: '选择图像保存位置', filename: `PLanB制图${new Date().getTime()}.jpg`, data: domImageBoard.value?.toDataURL("image/jpeg") })
			break;
		default:
			break
	}
}

//从文件获取图像数据
const getImageFromFile = (file: any) => {
	return new Promise(resolve => {
		const reader = new FileReader();
		reader.onload = function (e: any) {
			const base64 = e.target.result;
			// 在这里使用base64，例如可以将其设置到图片的src属性
			const image = new Image()
			image.src = base64
			image.onload = () => {
				resolve(image)
			}
		};
		reader.readAsDataURL(file); // 读取文件并转换为Base64
	})
}

//渲染canvas上的图像 (config:画图过程中的配置，after：执行完毕回调)
const renderImage = async (config?: any) => {
	return new Promise(resolve => {
		let width, height //canvas的宽高
		let { scale, rotate, image } = config ?? {} //TODO：还没考虑放大缩小
		const { width: iw, height: ih } = imageData.value
		var tmpCanvas = document.createElement('canvas');
		tmpCanvas.width = rotate ? ih : iw
		tmpCanvas.height = rotate ? iw : ih
		var tmpCtx: any = tmpCanvas.getContext('2d') ?? {};
		if (rotate) {
			tmpCtx.save();
			tmpCtx.rotate(Math.PI / 2)
			tmpCtx.drawImage(imageData.value, 0, -tmpCanvas.width, tmpCanvas.height, tmpCanvas.width)
			tmpCtx.restore();
		} else if (image) {
			tmpCtx.save();
			tmpCtx.translate(tmpCanvas.width, 0)
			tmpCtx.scale(-1, 1);
			tmpCtx.drawImage(imageData.value, tmpCanvas.width, 0, -tmpCanvas.width, tmpCanvas.height);
			tmpCtx.restore();
		} else {
			tmpCtx.drawImage(imageData.value, 0, 0, tmpCanvas.width, tmpCanvas.height);
		}
		getImageFromBase64(tmpCanvas.toDataURL("image/png")).then((imgData: any) => {
			imageData.value = imgData
			const container = document.querySelector('.main-content.img-edit') as HTMLElement;//获取父容器宽高
			//根据父框的宽高，计算出合适的canvas宽高，以达到canvas适应屏幕
			const containerWidth = Math.floor(container?.offsetWidth * 0.95)
			const containerHeight = Math.floor(container.offsetHeight * 0.95)
			const imageWidth = (rotate ? ih : iw)
			const imageHeight = (rotate ? iw : ih)
			//计算fit尺寸
			const containerRate = containerWidth / containerHeight
			const imgRate = imageWidth / imageHeight
			if (containerRate >= imgRate) {
				height = containerHeight
				width = Math.floor(height * imgRate)

			} else {
				width = containerWidth
				height = Math.floor(width / imgRate)
			}
			//动态调整画板宽高以及像素宽高
			canvasBlock.value.w = width
			canvasBlock.value.h = height
			canvasBlock.value.rw = imageWidth
			canvasBlock.value.rh = imageHeight
			nextTick(() => {
				const ctx: any = domImageBoard.value?.getContext('2d') ?? {}
				ctx.drawImage(imageData.value, 0, 0, imageWidth, imageHeight)
				resolve(null)
			})
		})
	})
}

//Base64转图像数据
const getImageFromBase64 = (base64: any) => {
	return new Promise(resolve => {
		// 在这里使用base64，例如可以将其设置到图片的src属性
		const image = new Image()
		image.src = base64
		image.onload = () => {
			resolve(image)
		}
	})
}


/*========================================>( 监听方法 )<========================================*/

//监听标题栏菜单返回
const handelBarMenusSelected = (mark: string) => {
	handleOperate(mark)
}

//监听图像拾取到
const handleImageLoad = async (file: any) => {
	fileName.value = file.name
	_filePath = file.path
	const allowTypes = ['image/jpeg', 'image/png', 'image/bmp', 'bmp']
	const isLt20M = file.size / 1024 / 1024 < 20;
	if (allowTypes.indexOf(file.type) == -1) {
		proxy?.$modal.notifyError('图片格式不支持')
		return false
	}
	if (!isLt20M) {
		proxy?.$modal.notifyError('图片大小不能超过 10MB!')
		return false
	}
	imageData.value = await getImageFromFile(file)
	//初始化历史列表
	renderImage().then(() => {
		saveHistory()
	})
	return false
}

//执行旋转
const dealRotate = () => {
	renderImage({ rotate: true }).then(() => {
		saveHistory()
	})
}

//执行镜像
const dealImage = () => {
	renderImage({ image: true }).then(() => {
		saveHistory()
	})
}

//执行裁剪
const dealCrop = async () => {
	if (!_cropLocation) return
	const [x, y, ex, ey] = _cropLocation || []
	const { rw, w } = canvasBlock.value
	const rate = rw / w
	var tmpCanvas = document.createElement('canvas');
	tmpCanvas.width = (ex - x) * rate
	tmpCanvas.height = (ey - y) * rate
	var tmpCtx = tmpCanvas.getContext('2d');
	tmpCtx?.drawImage(imageData.value, x * rate, y * rate, tmpCanvas.width, tmpCanvas.height, 0, 0, tmpCanvas.width, tmpCanvas.height)
	imageData.value = await getImageFromBase64(tmpCanvas.toDataURL("image/png"))
	renderImage().then(() => {
		saveHistory()
	})
}

//存照排版
const dealPassport = async () => {
	if (!imageData.value) return
	const iamgeRate = Number((canvasBlock.value.w / canvasBlock.value.h).toFixed(2))
	let inchType: string | undefined = undefined //图像尺寸
	if (iamgeRate >= 0.70 && iamgeRate <= 0.72) {
		inchType = 'Inch1'
	}
	if (iamgeRate >= 0.77 && iamgeRate <= 0.79) {
		inchType = 'Inch2'
	}
	if (!inchType) {
		proxy?.$modal.notifyError('请先裁剪至寸照比例')
		return
	}
	//打开子窗口，进行排版设置
	openChildWindow({ width: 400, height: 300, hash: 'img_edit/passport?i=' + inchType })
	_passportImageCache = await getImageFromBase64(domImageBoard.value?.toDataURL("image/png"))
}

//开始排版
const makePassport = (e: any) => {
	const { paper, inchType, passportCount } = e
	const base64 = createPassportPageBase64(_passportImageCache, paper, inchType, passportCount);
	getImageFromBase64(base64).then((d: any) => {
		imageData.value = d
		renderImage().then(() => {
			saveHistory()
			proxy?.$modal.closeLoading()
		})

	})
}

//取消框选
const clearSelect = () => {
	_isSelect = false
	_selectStart = undefined
	_cropLocation = undefined
	const canvas: any = domScreen?.value ?? {}
	const ctx: any = canvas.getContext('2d') ?? {}
	ctx.clearRect(0, 0, canvas.width, canvas.height);
}

//监听图像像素改变
const handleResolutionChanged = (e: any) => {
	showResolution.value = false
	proxy?.$modal.loading('处理中')
	setTimeout(() => {
		var tmpCanvas = document.createElement('canvas');//临时画板
		tmpCanvas.width = e.w
		tmpCanvas.height = e.h
		var tmpCtx = tmpCanvas.getContext('2d')
		if (!tmpCtx) return
		tmpCtx.drawImage(imageData.value, 0, 0, e.w, e.h);
		getImageFromBase64(tmpCanvas.toDataURL("image/png")).then((d: any) => {
			imageData.value = d
			renderImage().then(() => {
				saveHistory()
				proxy?.$modal.closeLoading()
				proxy?.$modal.alertSuccess('操作成功')
			})
		})
	}, 100)
}

//监听取消修改图像像素
const handleResolutionClose = () => {
	showResolution.value = false
}

//保存画板历史图像
const saveHistory = () => {
	//如果是中途储存
	_historyList.splice(_historyPointer + 1)
	_historyList.push(imageData.value)
	_historyPointer++
}

//渲染历史图像
const renderHistory = () => {
	imageData.value = _historyList[_historyPointer]
	renderImage()
}

//后退图像历史
const backHistory = () => {
	if (_historyPointer > 0) {
		_historyPointer--
		renderHistory()
	}
}

//前进图像历史
const forwardHistory = () => {
	if (_historyPointer < _historyList.length - 1) {
		_historyPointer++
		renderHistory()
	}
}

//重置图像
const resetImage = () => {
	if (_historyList.length) {
		_historyPointer = 0
		renderHistory()
	}
}

/*========================================>( dom监听 )<========================================*/
//监听鼠标按下
const listenCropMouseDown = (event: any) => {
	if(!imageData.value)return
	const canvas: any = domScreen.value ?? {}
	//储存起点坐标
	const { w: maxWidth, h: maxHeight } = canvasBlock.value
	//判断x
	const cx = event.clientX - canvas.offsetLeft
	const x = cx > 0 ? (cx > maxWidth ? maxWidth : cx) : 0
	//判断y
	const cy = event.clientY - canvas.offsetTop - 40
	const y = cy > 0 ? (cy > maxHeight ? maxHeight : cy) : 0
	_selectStart = [x, y]
	_isSelect = true
}

//监听鼠标移动
const listenCropMouseMove = (event: any) => {
	if (!_selectStart) return
	if (!_isSelect) return
	const canvas: any = domScreen.value ?? {}
	const ctx: any = canvas.getContext('2d') ?? {}
	const [sx, sy] = _selectStart
	let nowMouseX = 0
	let nowMouseY = 0
	const cx = (event.clientX - canvas.offsetLeft)
	const cy = (event.clientY - canvas.offsetTop - 40)
	//内部方法:按照比例框选 r 宽高比
	const calcRateXY = (r?: number) => {
		nowMouseX = cx
		if (r) {
			if (cy > sy) {
				nowMouseY = sy + Math.abs(nowMouseX - sx) / r
			} else {
				nowMouseY = sy - Math.abs(nowMouseX - sx) / r
			}
		} else {
			nowMouseY = cy
		}
		const { w: maxMouseX, h: maxMouseY } = canvasBlock.value
		if (nowMouseX >= maxMouseX || nowMouseX < 0) {
			return false
		}
		if (nowMouseY >= maxMouseY || nowMouseY < 0) {
			return false
		}
		return true
	}
	switch (selectType.value) {
		case 'select-type-freedom':
			if (!calcRateXY()) return
			break
		case 'select-type-square':
			if (!calcRateXY(1)) return
			break
		case 'select-type-2inch':
			if (!calcRateXY(3.5 / 4.5)) return
			break
		case 'select-type-1inch':
			if (!calcRateXY(2.5 / 3.5)) return
			break
		case 'select-type-yourself':
			if (!selectRateW.value) {
				selectRateW.value = 1
			}
			if (!selectRateH.value) {
				selectRateH.value = 1
			}
			if (!calcRateXY(selectRateW.value / selectRateH.value)) return
			break
	}
	ctx.clearRect(0, 0, canvas.width, canvas.height);//先清空
	//计算路径，先按不规则
	ctx.beginPath()
	ctx.moveTo(sx, sy);
	ctx.lineTo(sx, nowMouseY);
	ctx.lineTo(nowMouseX, nowMouseY);
	ctx.lineTo(nowMouseX, sy);
	ctx.lineTo(sx, sy);
	ctx.closePath();
	ctx.setLineDash([5, 5]);
	ctx.lineWidth = 1;
	ctx.strokeStyle = '#FFFFFF';
	ctx.shadowColor = '#000000'; // 阴影颜色
	ctx.shadowBlur = 1;       // 阴影模糊度
	ctx.shadowOffsetX = 1;     // 阴影水平偏移量
	ctx.shadowOffsetY = 1;
	ctx.stroke();
	//储存截图坐标点【topX,topY,bottomX,bottomY】
	_cropLocation = [Math.min(_selectStart[0], nowMouseX), Math.min(_selectStart[1], nowMouseY), Math.max(_selectStart[0], nowMouseX), Math.max(_selectStart[1], nowMouseY)]
}

//监听鼠标抬起
const listenCropMouseUpOrLeave = (event: any) => {
	_isSelect = false
}

/*========================================>( 钩子 )<========================================*/
onMounted(() => {
	initListener()
	ipcs.init()
	//监听并自适应element窗口
	window.addEventListener("resize", (e) => {
		nextTick(() => {
			if (imageData.value) {
				renderImage()
			}
		})
	})
})
</script>
<template>
	<MenuBar mid="ModuleImgEdit" title="JPG编辑器" barColor="#222" :menus="menuBarMenus" @select="handelBarMenusSelected" />
	<div class="main-content img-edit">
		<canvas v-if="imageData" ref="domImageBoard" :width="canvasBlock.rw" :height="canvasBlock.rh" :style="{ width: `${canvasBlock.w}px`, height: `${canvasBlock.h}px` }"></canvas>
		<canvas class="canvas-screen" v-if="imageData" ref="domScreen" :width="canvasBlock.w" :height="canvasBlock.h" :style="{ width: `${canvasBlock.w}px`, height: `${canvasBlock.h}px` }"></canvas>
		<el-upload v-show="!imageData" action="" class="img-picker" drag accept=".jpg,.jpeg,.png,.bmp" :show-file-list="false" :before-upload="handleImageLoad">
			<svg-icon ref="domUpload" icon-class="image-add" width="80" height="80" />
			<div class="el-upload__text">拖拽或点击打开图像</div>
		</el-upload>
		<div v-if="selectType === 'select-type-yourself'" class="select-type-yourself">
			<el-row :gutter="20">
				<el-col :span="4">宽:</el-col>
				<el-col :span="8">
					<el-input size="small" onkeyup="value=value.replace(/^0+/g, '').replace(/[^\d]/g,'')" v-model="selectRateW" />
				</el-col>
				<el-col :span="4">高:</el-col>
				<el-col :span="8">
					<el-input size="small" onkeyup="value=value.replace(/^0+/g, '').replace(/[^\d]/g,'')" v-model="selectRateH" />
				</el-col>
			</el-row>
		</div>
	</div>
	<el-dialog v-model="showOCR" title="解析到内容" width="500" :before-close="() => { showOCR = false }">
		<el-input v-model="ocrContent" style="width: 100%" :rows="10" type="textarea" placeholder="没有内容" readonly />
		<template #footer>
			<div class="dialog-footer">
				<el-button type="primary" @click="showOCR = false"> 确定 </el-button>
			</div>
		</template>
	</el-dialog>
	<Resolution v-if="showResolution" :resolution="resolution" @submit="handleResolutionChanged" @close="handleResolutionClose" />
</template>
<style lang="scss">
.main-content.img-edit {
	position: relative;
	width: 100vw;
	height: calc(100vh - 40px);
	overflow: hidden;
	background-color: #3d3d3d;
	display: flex;
	justify-content: center;
	align-items: center;
	-webkit-user-select: none;
	/* Chrome, Safari, Opera */
	-moz-user-select: none;
	/* Firefox */
	-ms-user-select: none;
	/* Internet Explorer/Edge */
	user-select: none;

	.canvas-screen {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		margin: auto;
	}

	.select-type-yourself {
		width: 140px;
		height: 30px;
		position: absolute;
		top: 0;
		right: 0;
		background-color: #000;
		display: flex;
		justify-content: center;
		align-items: center;
		opacity: 0.3;
		padding: 0 5px;
		color: #e1e1e1;

		&:hover {
			opacity: 1;
		}
	}

	.img-picker {
		width: 100%;
		height: 100%;

		.el-upload {
			width: 100%;
			height: 100%;
			background-color: #3d3d3d;
			cursor: inherit !important;

			.el-upload-dragger {
				width: 100%;
				height: 100%;
				background-color: #3d3d3d;
				color: #9999FF;
				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;
				cursor: inherit !important;
				border: 0 !important;

				.el-upload__text {
					padding: 7px 0 80px 0;
					color: #ccc !important;
				}
			}
		}
	}
}
</style>
<style lang="scss" scoped></style>
